<!DOCTYPE html>
<html class="writer-html5" lang="zh" >
<head>
  <meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />

  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Ch3-8 查询 &mdash; EasyVulkan</title>
      <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
      <link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
      <link rel="stylesheet" href="_static/theme.css" type="text/css" />
  <!--[if lt IE 9]>
    <script src="_static/js/html5shiv.min.js"></script>
  <![endif]-->
  
        <script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
        <script src="_static/jquery.js"></script>
        <script src="_static/underscore.js"></script>
        <script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
        <script src="_static/doctools.js"></script>
    <script src="_static/js/theme.js"></script>
    <link rel="index" title="索引" href="genindex.html" />
    <link rel="search" title="搜索" href="search.html" />
    <link rel="next" title="Ch4-1 着色器模组" href="Ch4-1%20%E7%9D%80%E8%89%B2%E5%99%A8%E6%A8%A1%E7%BB%84.html" />
    <link rel="prev" title="Ch3-7 采样器" href="Ch3-7%20%E9%87%87%E6%A0%B7%E5%99%A8.html" /> 
</head>

<body class="wy-body-for-nav"> 
  <div class="wy-grid-for-nav">
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >
            <a href="index.html" class="icon icon-home"> EasyVulkan
            <img src="_static/logo1.png" class="logo" alt="Logo"/>
          </a>
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="search.html" method="get">
    <input type="text" name="q" placeholder="在文档中搜索" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>
        </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
              <p class="caption" role="heading"><span class="caption-text">第一章 初始化</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch1-0%20%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C.html">Ch1-0 准备工作</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch1-1%20%E5%88%9B%E5%BB%BAGLFW%E7%AA%97%E5%8F%A3.html">Ch1-1 创建GLFW窗口</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch1-2%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%B5%81%E7%A8%8B.html">Ch1-2 初始化流程</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch1-3%20%E5%88%9B%E5%BB%BAVK%E5%AE%9E%E4%BE%8B%E4%B8%8E%E9%80%BB%E8%BE%91%E8%AE%BE%E5%A4%87.html">Ch1-3 创建VK实例与逻辑设备</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch1-4%20%E5%88%9B%E5%BB%BA%E4%BA%A4%E6%8D%A2%E9%93%BE.html">Ch1-4 创建交换链</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第二章 绘制一个三角形</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch2-0%20%E4%BB%A3%E7%A0%81%E6%95%B4%E7%90%86%E5%8F%8A%E4%B8%80%E4%BA%9B%E8%BE%85%E5%8A%A9%E7%B1%BB.html">Ch2-0 代码整理及一些辅助类</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch2-1%20Rendering%20Loop.html">Ch2-1 Rendering Loop</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch2-2%20%E5%88%9B%E5%BB%BA%E6%B8%B2%E6%9F%93%E9%80%9A%E9%81%93%E5%92%8C%E5%B8%A7%E7%BC%93%E5%86%B2.html">Ch2-2 创建渲染通道和帧缓冲</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch2-3%20%E5%88%9B%E5%BB%BA%E7%AE%A1%E7%BA%BF%E5%B9%B6%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2.html">Ch2-3 创建管线并绘制三角形</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第三章 纵观Vulkan</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="Ch3-1%20%E5%90%8C%E6%AD%A5%E5%8E%9F%E8%AF%AD.html">Ch3-1 同步原语</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch3-2%20%E5%9B%BE%E5%83%8F%E4%B8%8E%E7%BC%93%E5%86%B2%E5%8C%BA.html">Ch3-2 图像与缓冲区</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch3-3%20%E7%AE%A1%E7%BA%BF%E5%B8%83%E5%B1%80%E5%92%8C%E7%AE%A1%E7%BA%BF.html">Ch3-3 管线布局和管线</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch3-4%20%E6%B8%B2%E6%9F%93%E9%80%9A%E9%81%93%E5%92%8C%E5%B8%A7%E7%BC%93%E5%86%B2.html">Ch3-4 渲染通道和帧缓冲</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch3-5%20%E5%91%BD%E4%BB%A4%E7%BC%93%E5%86%B2%E5%8C%BA.html">Ch3-5 命令缓冲区</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch3-6%20%E6%8F%8F%E8%BF%B0%E7%AC%A6.html">Ch3-6 描述符</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch3-7%20%E9%87%87%E6%A0%B7%E5%99%A8.html">Ch3-7 采样器</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Ch3-8 查询</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#query-pool">Query Pool</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#id1">创建查询池</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id2">开始和结束查询</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id3">获取查询结果</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id4">重置查询</a></li>
<li class="toctree-l3"><a class="reference internal" href="#querypool">封装为queryPool类</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#id5">遮挡查询</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#id6">创建遮挡查询</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id7">开始和结束遮挡查询</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id8">封装</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#id9">管线统计查询</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#id10">创建管线统计查询</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id11">封装</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="#id12">时间戳查询</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#id13">写入时间戳</a></li>
<li class="toctree-l3"><a class="reference internal" href="#id14">封装</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第四章 着色器</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch4-1%20%E7%9D%80%E8%89%B2%E5%99%A8%E6%A8%A1%E7%BB%84.html">Ch4-1 着色器模组</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch4-2%20%E9%A1%B6%E7%82%B9%E7%9D%80%E8%89%B2%E5%99%A8.html">Ch4-2 顶点着色器</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch4-3%20%E7%89%87%E6%AE%B5%E7%9D%80%E8%89%B2%E5%99%A8.html">Ch4-3 片段着色器</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch4-4%20%E5%87%A0%E4%BD%95%E7%9D%80%E8%89%B2%E5%99%A8.html">Ch4-4 几何着色器</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第五章 封装常用对象</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch5-0%20VKBase%2B.h.html">Ch5-0 VKBase+.h</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch5-1%20%E5%90%84%E7%A7%8D%E7%BC%93%E5%86%B2%E5%8C%BA.html">Ch5-1 各种缓冲区</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch5-2%202D%E8%B4%B4%E5%9B%BE%E5%8F%8A%E7%94%9F%E6%88%90Mipmap.html">Ch5-2 2D贴图及生成Mipmap</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch5-3%202D%E8%B4%B4%E5%9B%BE%E6%95%B0%E7%BB%84.html">Ch5-3 2D贴图数组</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第六章 进阶Vulkan</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch6-0%20%E4%BD%BF%E7%94%A8%E6%96%B0%E7%89%88%E6%9C%AC%E7%89%B9%E6%80%A7.html">Ch6-0 使用新版本特性</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch6-1%20%E6%97%A0%E5%9B%BE%E5%83%8F%E5%B8%A7%E7%BC%93%E5%86%B2.html">Ch6-1 无图像帧缓冲</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch6-2%20%E5%8A%A8%E6%80%81%E6%B8%B2%E6%9F%93.html">Ch6-2 动态渲染</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第七章 基础示例</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch7-1%20%E5%88%9D%E8%AF%86%E9%A1%B6%E7%82%B9%E7%BC%93%E5%86%B2%E5%8C%BA.html">Ch7-1 初识顶点缓冲区</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch7-2%20%E5%88%9D%E8%AF%86%E7%B4%A2%E5%BC%95%E7%BC%93%E5%86%B2%E5%8C%BA.html">Ch7-2 初识索引缓冲区</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch7-3%20%E5%88%9D%E8%AF%86%E5%AE%9E%E4%BE%8B%E5%8C%96%E7%BB%98%E5%88%B6.html">Ch7-3 初识实例化绘制</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch7-4%20%E5%88%9D%E8%AF%86Push%20Constant.html">Ch7-4 初识Push Constant</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch7-5%20%E5%88%9D%E8%AF%86Uniform%E7%BC%93%E5%86%B2%E5%8C%BA.html">Ch7-5 初识Uniform缓冲区</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch7-6%20%E6%8B%B7%E8%B4%9D%E5%9B%BE%E5%83%8F%E5%88%B0%E5%B1%8F%E5%B9%95.html">Ch7-6 拷贝图像到屏幕</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch7-7%20%E4%BD%BF%E7%94%A8%E8%B4%B4%E5%9B%BE.html">Ch7-7 使用贴图</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">第八章 简单示例</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ch8-1%20%E7%A6%BB%E5%B1%8F%E6%B8%B2%E6%9F%93.html">Ch8-1 离屏渲染</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch8-2%20%E6%B7%B1%E5%BA%A6%E6%B5%8B%E8%AF%95%E5%92%8C%E6%B7%B1%E5%BA%A6%E5%8F%AF%E8%A7%86%E5%8C%96.html">Ch8-2 深度测试和深度可视化</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch8-3%20%E5%BB%B6%E8%BF%9F%E6%B8%B2%E6%9F%93.html">Ch8-3 延迟渲染</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch8-4%20%E9%A2%84%E4%B9%98Alpha.html">Ch8-4 预乘Alpha</a></li>
<li class="toctree-l1"><a class="reference internal" href="Ch8-5%20sRGB%E8%89%B2%E5%BD%A9%E7%A9%BA%E9%97%B4%E4%B8%8E%E5%BC%80%E5%90%AFHDR.html">Ch8-5 sRGB色彩空间与开启HDR</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">附录</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="Ap1-1%20%E8%BF%90%E8%A1%8C%E6%9C%9F%E7%BC%96%E8%AF%91GLSL.html">Ap1-1 运行期编译GLSL</a></li>
</ul>

        </div>
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="index.html">EasyVulkan</a>
      </nav>

      <div class="wy-nav-content">
        <div class="rst-content">
          <div role="navigation" aria-label="Page navigation">
  <ul class="wy-breadcrumbs">
      <li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
      <li>Ch3-8 查询</li>
      <li class="wy-breadcrumbs-aside">
      </li>
  </ul>
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
             
  <section id="ch3-8">
<h1>Ch3-8 查询<a class="headerlink" href="#ch3-8" title="Permalink to this heading"></a></h1>
<p>
    Vulkan中提供了一种用来取得Vulkan命令执行信息的机制，称之为查询（query）。
</p><section id="query-pool">
<h2>Query Pool<a class="headerlink" href="#query-pool" title="Permalink to this heading"></a></h2>
<p>
    查询池（<span class="type">VkQueryPool</span>）是用于管理查询的Vulkan对象。
</p><section id="id1">
<h3>创建查询池<a class="headerlink" href="#id1" title="Permalink to this heading"></a></h3>
<p>
    用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCreateQueryPool">vkCreateQueryPool</a>(...)创建查询池：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="type">VkResult</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCreateQueryPool">vkCreateQueryPool</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkDevice</span> device</p></td>
            <td><p>逻辑设备的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="kw">const</span> <span class="type">VkQueryPoolCreateInfo</span>* pCreateInfo</p></td>
            <td><p>指向<span class="type">VkQueryPool</span>的创建信息</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="kw">const</span> <span class="type">VkAllocationCallbacks</span>* pAllocator</p></td>
            <td><p></p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span>* pQueryPool</p></td>
            <td><p>若执行成功，将查询池的handle写入*pQueryPool</p></td>
        </tr>
    </tbody>
</table>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">struct</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#VkQueryPoolCreateInfo">VkQueryPoolCreateInfo</a> 的成员说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkStructureType</span> sType</p></td>
            <td><p>结构体的类型，本处必须是<span class="enum">VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO</span></p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="kw">const void</span>* pNext</p></td>
            <td><p>如有必要，指向一个用于扩展该结构体的结构体</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkQueryPoolCreateFlags</span> flags</p></td>
            <td><p>到Vulkan1.3为止没用</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryType</span> queryType</p></td>
            <td><p>查询的类型</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> queryCount</p></td>
            <td><p>查询的个数</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPipelineStatisticFlags</span> pipelineStatistics</p></td>
            <td><p>如果查询的类型为管线统计查询，在此指定需要进行哪些统计</p></td>
        </tr>
    </tbody>
</table>
<table class="docutils align-default">
    <colgroup>
        <col>
        <col>
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head"><p>版本要求</p></th>
            <th class="head"><p><a href="https://renderdoc.org/vkspec_chunked/chap18.html#VkQueryType">VkQueryType</a> 的枚举项</p></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_TYPE_OCCLUSION </span>表示遮挡查询</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_TYPE_PIPELINE_STATISTICS </span>表示管线统计查询</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_TYPE_TIMESTAMP </span>表示时间戳查询</p></td>
        </tr>
    </tbody>
</table></section>
<section id="id2">
<h3>开始和结束查询<a class="headerlink" href="#id2" title="Permalink to this heading"></a></h3>
<p>
    在Vulkan核心功能提供的三种查询中，遮挡查询和管线统计查询基于一定范围发生，有开始和结束。
</p>
<p>
    在命令缓冲区中，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdBeginQuery">vkCmdBeginQuery</a>(...)标记查询范围的起始：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">void</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdBeginQuery">vkCmdBeginQuery</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkCommandBuffer</span> commandBuffer</p></td>
            <td><p>命令缓冲区的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> query</p></td>
            <td><p>要开始的查询的索引</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryControlFlags</span> flags</p></td>
            <td><p>自Vulkan1.0到1.3，<span class="enum">VK_QUERY_CONTROL_PRECISE_BIT</span>是唯一可用的bit，相关说明见后文的遮挡查询</p></td>
        </tr>
    </tbody>
</table>
<p>
    在命令缓冲区中，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdEndQuery">vkCmdEndQuery</a>(...)标记查询范围的结束：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">void</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdEndQuery">vkCmdEndQuery</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkCommandBuffer</span> commandBuffer</p></td>
            <td><p>命令缓冲区的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> query</p></td>
            <td><p>要结束的查询的索引</p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            如果查询在渲染通道外开始，相应地得在渲染通道外结束。
            <br>
            如果查询在渲染通道内开始，相应地得在该渲染通道的同一子通道内结束。
        </p>
    </li>
<ul></section>
<section id="id3">
<h3>获取查询结果<a class="headerlink" href="#id3" title="Permalink to this heading"></a></h3>
<p>
    在命令缓冲区中，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdCopyQueryPoolResults">vkCmdCopyQueryPoolResults</a>(...)将查询结果拷贝到数据缓冲区：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">void</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdCopyQueryPoolResults">vkCmdCopyQueryPoolResults</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkCommandBuffer</span> commandBuffer</p></td>
            <td><p>命令缓冲区的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> firstQuery</p></td>
            <td><p>首个要被拷贝结果的查询的索引</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">uint32_t</span> queryCount</p></td>
            <td><p>要被拷贝结果的查询的个数</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkBuffer</span> dstBuffer</p></td>
            <td><p>目标缓冲区</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkDeviceSize</span> dstOffset</p></td>
            <td><p>查询结果要被拷贝到目标缓冲区中的位置，单位是字节，必须是4的倍数（或8的倍数，见后文）</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkDeviceSize</span> stride</p></td>
            <td><p>每组查询结果在目标缓冲区中的间距，单位是字节，必须是4的倍数（或8的倍数，见后文）</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkQueryResultFlagBits</span> flags</p></td>
            <td><p></p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            若queryCount为1，stride可以为0。
        </p>
    </li>
</ul>
<table class="docutils align-default">
    <colgroup>
        <col>
        <col>
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head"><p>版本要求</p></th>
            <th class="head"><p><a href="https://renderdoc.org/vkspec_chunked/chap18.html#VkQueryResultFlagBits">VkQueryResultFlagBits</a> 的枚举项</p></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_RESULT_64_BIT                </span>如不注明该bit，获取到的每个查询结果为4字节无符号整形，注明该bit时为8字节</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_RESULT_WAIT_BIT              </span>表示在获取查询结果前，等待查询的完成</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_RESULT_WITH_AVAILABILITY_BIT </span>见后文</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_RESULT_PARTIAL_BIT           </span>见后文</p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            注明<span class="enum">VK_QUERY_RESULT_64_BIT</span>时，dstOffset和stride也相应地须是8的倍数。
        </p>
    </li>
    <li>
        <p>
            <span class="enum">VK_QUERY_RESULT_WITH_AVAILABILITY_BIT </span>表示在每组查询结果尾端添加一个数值，用于表示是否已完成查询，未完成时为0，已完成则非零。
            <br>
            该数值的字节数同查询结果一样，受<span class="enum">VK_QUERY_RESULT_64_BIT</span>影响。
        </p>
    </li>
    <li>
        <p>
            若注明<span class="enum">VK_QUERY_RESULT_PARTIAL_BIT</span>，查询尚未完成时获取到的结果，是查询过程中的中间结果。
            <br>
            若没有注明<span class="enum">VK_QUERY_RESULT_PARTIAL_BIT</span>，且查询尚未完成，获取到的查询结果未定义（可能是任意不准确的数值）。
        </p>
    </li>
    <li>
        <p>
            <span class="enum">VK_QUERY_RESULT_PARTIAL_BIT</span>不适用于时间戳查询（时间戳查询没有操作范围，“写入时间戳”是瞬间性的操作）。
        </p>
    </li>
</ul>
<p>
    <span class="fn">vkCmdCopyQueryPoolResults</span>(...)适用于可以在GPU侧直接处理查询结果的情形，比如实现GPU-driven的遮挡剔除。
    <br>
    对于管线统计查询和时间戳查询，你可能会更倾向于把查询结果拷贝到主机一侧（要将查询结果显示到屏幕，用计算着色器根据数值生成字符的顶点数据是可行的，不过大部分人应该会用开源GUI的功能来绘制吧）。
</p>
<p>
    在主机（CPU）一侧，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkGetQueryPoolResults">vkGetQueryPoolResults</a>(...)获取查询结果：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="type">VkResult</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkGetQueryPoolResults">vkGetQueryPoolResults</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkDevice</span> device</p></td>
            <td><p>逻辑设备的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> firstQuery</p></td>
            <td><p>首个要被拷贝结果的查询的索引</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">uint32_t</span> queryCount</p></td>
            <td><p>要被拷贝结果的查询的个数</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">size_t</span> dataSize</p></td>
            <td><p>pData所指向的内存区的容量（虽然该参数如此命名，并不是要你填查询结果的大小），大小须能容纳queryCount个查询结果</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="kw">void</span>* pData</p></td>
            <td><p>查询结果被拷贝到pData所指向的内存区</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkDeviceSize</span> stride</p></td>
            <td><p>每组查询结果在目标内存区中的间距，单位是字节，必须是4的倍数（或8的倍数，见前文）</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkQueryResultFlagBits</span> flags</p></td>
            <td><p></p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            函数执行成功时，除了<span class="enum">VK_SUCCESS</span>还可能会返回<span class="enum">VK_NOT_READY</span>（值为1），表示查询尚未结束。
        </p>
    </li>
</ul></section>
<section id="id4">
<h3>重置查询<a class="headerlink" href="#id4" title="Permalink to this heading"></a></h3>
<p>
    开始查询前（包括首次开始），必须重置查询。
</p>
<p>
    在命令缓冲区中，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdResetQueryPool">vkCmdResetQueryPool</a>(...)重置查询：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">void</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdResetQueryPool">vkCmdResetQueryPool</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkCommandBuffer</span> commandBuffer</p></td>
            <td><p>命令缓冲区的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> firstQuery</p></td>
            <td><p>首个要被重置的查询的索引</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">uint32_t</span> queryCount</p></td>
            <td><p>要被重置的查询的个数</p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            必须在渲染通道之外重置查询。
        </p>
    </li>
</ul>
<p>
    自Vulkan1.2起，可以在主机（CPU）一侧，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkResetQueryPool">vkResetQueryPool</a>(...)重置查询：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">void</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkResetQueryPool">vkResetQueryPool</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkDevice</span> device</p></td>
            <td><p>逻辑设备的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">uint32_t</span> firstQuery</p></td>
            <td><p>首个要被重置的查询的索引</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">uint32_t</span> queryCount</p></td>
            <td><p>要被重置的查询的个数</p></td>
        </tr>
    </tbody>
</table></section>
<section id="querypool">
<h3>封装为queryPool类<a class="headerlink" href="#querypool" title="Permalink to this heading"></a></h3>
<p>
    接下来先对<span class="type">VkQueryPool</span>进行封装，再逐一解说Vulkan核心功能中提供的三种查询类型及相关函数。
    <br>
    向<span class="path">VKBase.h</span>，vulkan命名空间中添加以下代码：
</p>
<pre class="code">
<span class="kw">class</span> <span class="type">queryPool</span> {
    <span class="type">VkQueryPool</span> handle = <span class="mcr">VK_NULL_HANDLE</span>;
<span class="kw">public</span>:
    <span class="fn">queryPool</span>() = <span class="kw">default</span>;
    <span class="fn">queryPool</span>(<span class="type">VkQueryPoolCreateInfo</span>&amp; <span class="par">createInfo</span>) {
        <span class="fn">Create</span>(<span class="par">createInfo</span>);
    }
    <span class="fn">queryPool</span>(<span class="type">VkQueryType</span> <span class="par">queryType</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>, <span class="type">VkQueryPipelineStatisticFlags</span> <span class="par">pipelineStatistics</span> = 0 <span class="cmt">/*VkQueryPoolCreateFlags flags*/</span>) {
        <span class="fn">Create</span>(<span class="par">queryType</span>, <span class="par">queryCount</span>, <span class="par">pipelineStatistics</span>);
    }
    <span class="fn">queryPool</span>(<span class="type">queryPool</span>&amp;&amp; <span class="par">other</span>) <span class="kw">noexcept</span> { <span class="mcr">MoveHandle</span>; }
    <span class="fn">~queryPool</span>() { <span class="mcr">DestroyHandleBy</span>(<span class="fn">vkDestroyQueryPool</span>); }
    <span class="cmt">//Getter</span>
    <span class="mcr">DefineHandleTypeOperator</span>;
    <span class="mcr">DefineAddressFunction</span>;
    <span class="cmt">//Const Function</span>
    <span class="kw">void</span> <span class="fn">CmdReset</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">firstQueryIndex</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>) <span class="kw">const</span> {
        <span class="fn">vkCmdResetQueryPool</span>(<span class="par">commandBuffer</span>, handle, <span class="par">firstQueryIndex</span>, <span class="par">queryCount</span>);
    }
    <span class="kw">void</span> <span class="fn">CmdBegin</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>, <span class="type">VkQueryControlFlags</span> <span class="par">flags</span> = 0) <span class="kw">const</span> {
        <span class="fn">vkCmdBeginQuery</span>(<span class="par">commandBuffer</span>, handle, <span class="par">queryIndex</span>, <span class="par">flags</span>);
    }
    <span class="kw">void</span> <span class="fn">CmdEnd</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>) <span class="kw">const</span> {
        <span class="fn">vkCmdEndQuery</span>(<span class="par">commandBuffer</span>, handle, <span class="par">queryIndex</span>);
    }
    <span class="kw">void</span> <span class="fn">CmdWriteTimestamp</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">VkPipelineStageFlagBits</span> <span class="par">pipelineStage</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>) <span class="kw">const</span> {
        <span class="fn">vkCmdWriteTimestamp</span>(<span class="par">commandBuffer</span>, <span class="par">pipelineStage</span>, handle, <span class="par">queryIndex</span>);
    }
    <span class="kw">void</span> <span class="fn">CmdCopyResults</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">firstQueryIndex</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>,
        <span class="type">VkBuffer</span> <span class="par">buffer_dst</span>, <span class="type">VkDeviceSize</span> <span class="par">offset_dst</span>, <span class="type">VkDeviceSize</span> <span class="par">stride</span>, <span class="type">VkQueryResultFlags</span> <span class="par">flags</span> = 0) <span class="kw">const</span> {
        <span class="fn">vkCmdCopyQueryPoolResults</span>(<span class="par">commandBuffer</span>, handle, <span class="par">firstQueryIndex</span>, <span class="par">queryCount</span>, <span class="par">buffer_dst</span>,<span class="par">offset_dst</span>, <span class="par">stride</span>, <span class="par">flags</span>);
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>(<span class="type">uint32_t</span> <span class="par">firstQueryIndex</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>, <span class="type">size_t</span> <span class="par">dataSize</span>, <span class="kw">void</span>* <span class="par">pData_dst</span>, <span class="type">VkDeviceSize</span> <span class="par">stride</span>, <span class="type">VkQueryResultFlags</span> <span class="par">flags</span> = 0) <span class="kw">const</span> {
        <span class="type">VkResult</span> result = <span class="fn">vkGetQueryPoolResults</span>(<span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">Device</span>(), handle, <span class="par">firstQueryIndex</span>, <span class="par">queryCount</span>, <span class="par">dataSize</span>, <span class="par">pData_dst</span>, <span class="par">stride</span>, <span class="par">flags</span>);
        <span class="kw">if</span> (result)
            result > 0 ? <span class="cmt">//若返回值为VK_NOT_READY，则查询尚未结束，有查询结果尚不可获</span>
            outStream &lt;&lt; std::<span class="fn">format</span>(<span class="str">&quot;[ queryPool ] WARNING\nNot all queries are available!\nError code: {}\n&quot;</span>, <span class="type">int32_t</span>(result)) :
            outStream &lt;&lt; std::<span class="fn">format</span>(<span class="str">&quot;[ queryPool ] ERROR\nFailed to get query pool results!\nError code: {}\n&quot;</span>, <span class="type">int32_t</span>(result));
        <span class="kw">return</span> result;
    }
    <span class="cmt">/*Provided by VK_API_VERSION_1_2*/</span>
    <span class="kw">void</span> <span class="fn">Reset</span>(<span class="type">uint32_t</span> <span class="par">firstQueryIndex</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>) {
        <span class="fn">vkResetQueryPool</span>(<span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">Device</span>(), handle, <span class="par">firstQueryIndex</span>, <span class="par">queryCount</span>);
    }
    <span class="cmt">//Non-const Function</span>
    <span class="type">result_t</span> <span class="fn">Create</span>(<span class="type">VkQueryPoolCreateInfo</span>&amp; <span class="par">createInfo</span>) {
        <span class="par">createInfo</span>.sType = <span class="enum">VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO</span>;
        <span class="type">VkResult</span> result = <span class="fn">vkCreateQueryPool</span>(<span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">Device</span>(), &amp;<span class="par">createInfo</span>, <span class="kw">nullptr</span>, &amp;handle);
        <span class="kw">if</span> (result)
            outStream &lt;&lt; std::<span class="fn">format</span>(<span class="str">&quot;[ queryPool ] ERROR\nFailed to create a query pool!\nError code: {}\n&quot;</span>, <span class="type">int32_t</span>(result));
        <span class="kw">return</span> result;
    }
    <span class="type">result_t</span> <span class="fn">Create</span>(<span class="type">VkQueryType</span> <span class="par">queryType</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>, <span class="type">VkQueryPipelineStatisticFlags</span> <span class="par">pipelineStatistics</span> = 0 <span class="cmt">/*VkQueryPoolCreateFlags flags*/</span>) {
        <span class="type">VkQueryPoolCreateInfo</span> createInfo = {
            .queryType = <span class="par">queryType</span>,
            .queryCount = <span class="par">queryCount</span>,
            .pipelineStatistics = <span class="par">pipelineStatistics</span>
        };
        <span class="kw">return</span> <span class="fn">Create</span>(createInfo);
    }
};
</pre></section>
</section>
<section id="id5">
<h2>遮挡查询<a class="headerlink" href="#id5" title="Permalink to this heading"></a></h2>
<p>
    遮挡查询（occlusion query）可以统计绘制出的采样点的数量。
</p>
<p>
    没有通过深度测试和模板测试等早期/晚期片段测试的、覆盖率（见<a class="reference internal" href="Ch3-3%20%E7%AE%A1%E7%BA%BF%E5%B8%83%E5%B1%80%E5%92%8C%E7%AE%A1%E7%BA%BF.html#vkpipelinemultisamplestatecreateinfo">多重采样</a>和<a class="reference internal" href="Ch4-3%20%E7%89%87%E6%AE%B5%E7%9D%80%E8%89%B2%E5%99%A8.html#gl-samplemaskin">gl_SampleMaskIn</a>、<a class="reference internal" href="Ch4-3%20%E7%89%87%E6%AE%B5%E7%9D%80%E8%89%B2%E5%99%A8.html#gl-samplemask">gl_SampleMask</a>）为0的、在片段着色器中被<span class="kw">discard</span>的，这些采样点都算是“被遮挡”，不计入查询结果。
    <br>
    另外，管线混色状态中，若将<a class="reference internal" href="Ch3-3%20%E7%AE%A1%E7%BA%BF%E5%B8%83%E5%B1%80%E5%92%8C%E7%AE%A1%E7%BA%BF.html#vkpipelinecolorblendattachmentstate">VkPipelineColorBlendAttachmentState</a>::colorWriteMask指定为0（即关闭对RGBA四通道的颜色写入），则查询结果的计数不会增加。
    <br>
    先被绘制出来，之后被遮掉的采样点，当然计入查询结果（毕竟在计数的时候不知道后来会不会被遮掉）。
</p><section id="id6">
<h3>创建遮挡查询<a class="headerlink" href="#id6" title="Permalink to this heading"></a></h3>
<p>
    要创建遮挡查询，只需要指定查询类型和查询个数即可，每组查询结果是一个整形数值，于是：
</p>
<pre class="code">
<span class="kw">class</span> <span class="type">occlusionQueries</span> {
<span class="kw">protected</span>:
    <span class="type">queryPool</span> queryPool;
    std::<span class="type">vector</span>&lt;<span class="type">uint32_t</span>&gt; passingSampleCounts;
<span class="kw">public</span>:
    <span class="fn">occlusionQueries</span>() = <span class="kw">default</span>;
    <span class="fn">occlusionQueries</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        <span class="fn">Create</span>(<span class="par">capacity</span>);
    }
    <span class="cmt">//Getter</span>
    <span class="kw">operator</span> <span class="type">VkQueryPool</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool; }
    <span class="kw">const</span> <span class="type">VkQueryPool</span>* <span class="fn">Address</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool.<span class="fn">Address</span>(); }
    <span class="type">uint32_t</span> <span class="fn">Capacity</span>() <span class="kw">const</span> { <span class="kw">return</span> passingSampleCounts.<span class="fn">size</span>(); }
    <span class="type">uint32_t</span> <span class="fn">PassingSampleCount</span>(<span class="type">uint32_t</span> <span class="par">index</span>) <span class="kw">const</span> { <span class="kw">return</span> passingSampleCounts[<span class="par">index</span>]; }
    <span class="cmt">//Const Function</span>
    <span class="cmt">/*待填充*/</span>
    <span class="cmt">//Non-const Function</span>
    <span class="kw">void</span> <span class="fn">Create</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        passingSampleCounts.<span class="fn">resize</span>(<span class="par">capacity</span>); <span class="cmt">//使passingSampleCounts的元素个数等于查询池容量</span>
        queryPool.<span class="fn">Create</span>(<span class="enum">VK_QUERY_TYPE_OCCLUSION</span>, <span class="par">capacity</span>);
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>() {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(<span class="fn">Capacity</span>());
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>(<span class="type">uint32_t</span> <span class="par">queryCount</span>) {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(
            0,                          <span class="cmt">//firstQuery</span>
            <span class="par">queryCount</span>,                 <span class="cmt">//queryCount</span>
            <span class="par">queryCount</span> * 4,             <span class="cmt">//dataSize，内存区大小</span>
            passingSampleCounts.<span class="fn">data</span>(), <span class="cmt">//pData</span>
            4                           <span class="cmt">//stride，每组查询结果在目标内存区中的间距，这里是uint32_t的大小，即是紧密排列</span>
        );                              <span class="cmt">//使用该函数获取结果时应当有栅栏同步，无需注明VK_QUERY_RESULT_WAIT_BIT</span>
    }
};
</pre>
<ul>
    <li>
        <p>
            将查询结果获取为32位整数应该是足够了，除非你使用的硬件有夸张的运算性能（得绘制4096*4096大小的区域256次且没有采样点被丢弃，才能达到<span class="mcr">UINT32_MAX</span>）。
        </p>
    </il>
</ul>
<p>
    考虑需要变更查询池容量，重建查询池的情况：
</p>
<pre class="code">
<span class="kw">void</span> <span class="fn">Create</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
    passingSampleCounts.<span class="fn">resize</span>(<span class="par">capacity</span>);
    <span class="cmt">/*新增*/</span> passingSampleCounts.<span class="fn">shrink_to_fit</span>();
    queryPool.<span class="fn">Create</span>(<span class="enum">VK_QUERY_TYPE_OCCLUSION</span>, <span class="fn">Capacity</span>()); <span class="cmt">//capacity变为Capacity()</span>
}
<span class="kw">void</span> <span class="fn">Recreate</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
    <span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">WaitIdle</span>(); <span class="cmt">//重建查询池之前应确保物理设备没有在使用它</span>
    queryPool.<span class="fn">~queryPool</span>();
    <span class="fn">Create</span>(<span class="par">capacity</span>);
}
</pre>
<ul>
    <li>
        <p>
            用std::<span class="type">vector</span>::<span class="fn">resize</span>(...)重设一个<span class="type">vector</span>容器的元素数时，即便重设到更小容量，容器底层的堆内存大小也不会减少。
            <br>
            重设<span class="type">vector</span>容器到更小容量后，用std::<span class="type">vector</span>::<span class="fn">shrink_to_fit</span>()可以将底层的堆内存重新分配，以节省多余的容量。
        </p>
    </li>
</ul></section>
<section id="id7">
<h3>开始和结束遮挡查询<a class="headerlink" href="#id7" title="Permalink to this heading"></a></h3>
<p>
    若向<span class="fn">vkCmdBeginQuery</span>(...)的<span class="par">flags</span>参数填入<span class="enum">VK_QUERY_CONTROL_PRECISE_BIT</span>（值为1），则查询结果为最终保留下来的采样点个数的精确值（计数方法为实现特定，不同Vulkan实现提供的数值间可能略有偏差）。
</p>
<p>
    否则，应当将查询结果视为二值的：在有采样点被保留下来时的查询结果为非零值（对具体数值无要求），所有采样点皆不被保留时的查询结果为0。
    <br>
    注明<span class="enum">VK_QUERY_CONTROL_PRECISE_BIT</span>时的开销可能大于不注明该bit时的开销，在只需知晓是否会渲染出内容，而不关注具体的采样点数量时，<strong>不应</strong>注明该bit。
</p>
<pre class="code">
<span class="kw">void</span> <span class="fn">CmdBegin</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>, <span class="kw">bool</span> <span class="par">isPrecise</span> = <span class="kw">false</span>) <span class="kw">const</span> {
    queryPool.<span class="fn">CmdBegin</span>(<span class="par">commandBuffer</span>, <span class="par">queryIndex</span>, <span class="par">isPrecise</span>);
}
<span class="kw">void</span> <span class="fn">CmdEnd</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>) <span class="kw">const</span> {
    queryPool.<span class="fn">CmdEnd</span>(<span class="par">commandBuffer</span>, <span class="par">queryIndex</span>);
}
</pre></section>
<section id="id8">
<h3>封装<a class="headerlink" href="#id8" title="Permalink to this heading"></a></h3>
<p>
    完成剩余封装：
</p>
<pre class="code">
<span class="kw">class</span> <span class="type">occlusionQueries</span> {
<span class="kw">protected</span>:
    <span class="type">queryPool</span> queryPool;
    std::<span class="type">vector</span>&lt;<span class="type">uint32_t</span>&gt; passingSampleCounts;
<span class="kw">public</span>:
    <span class="fn">occlusionQueries</span>() = <span class="kw">default</span>;
    <span class="fn">occlusionQueries</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        <span class="fn">Create</span>(<span class="par">capacity</span>);
    }
    <span class="cmt">//Getter</span>
    <span class="kw">operator</span> <span class="type">VkQueryPool</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool; }
    <span class="kw">const</span> <span class="type">VkQueryPool</span>* <span class="fn">Address</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool.<span class="fn">Address</span>(); }
    <span class="type">uint32_t</span> <span class="fn">Capacity</span>() <span class="kw">const</span> { <span class="kw">return</span> passingSampleCounts.<span class="fn">size</span>(); }
    <span class="type">uint32_t</span> <span class="fn">PassingSampleCount</span>(<span class="type">uint32_t</span> <span class="par">index</span>) <span class="kw">const</span> { <span class="kw">return</span> passingSampleCounts[<span class="par">index</span>]; }
    <span class="cmt">//Const Function</span>
    <span class="cmt">/*重置整个查询池*/</span>
    <span class="kw">void</span> <span class="fn">CmdReset</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdReset</span>(<span class="par">commandBuffer</span>, 0, <span class="fn">Capacity</span>());
    }
    <span class="kw">void</span> <span class="fn">CmdBegin</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>, <span class="kw">bool</span> <span class="par">isPrecise</span> = <span class="kw">false</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdBegin</span>(<span class="par">commandBuffer</span>, <span class="par">queryIndex</span>, <span class="par">isPrecise</span>);
    }
    <span class="kw">void</span> <span class="fn">CmdEnd</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdEnd</span>(<span class="par">commandBuffer</span>, <span class="par">queryIndex</span>);
    }
    <span class="cmt">/*常用于GPU-driven遮挡剔除*/</span>
    <span class="kw">void</span> <span class="fn">CmdCopyResults</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">uint32_t</span> <span class="par">firstQueryIndex</span>, <span class="type">uint32_t</span> <span class="par">queryCount</span>,
        <span class="type">VkBuffer</span> <span class="par">buffer_dst</span>, <span class="type">VkDeviceSize</span> <span class="par">offset_dst</span>, <span class="type">VkDeviceSize</span> <span class="par">stride</span>) <span class="kw">const</span> {
        <span class="cmt">//需要等待查询结束以获取正确的数值，flags为VK_QUERY_RESULT_WAIT_BIT</span>
        queryPool.<span class="fn">CmdCopyResults</span>(<span class="par">commandBuffer</span>, <span class="par">firstQueryIndex</span>, <span class="par">queryCount</span>, <span class="par">buffer_dst</span>, <span class="par">offset_dst</span>,<span class="par">stride</span>, <span class="enum">VK_QUERY_RESULT_WAIT_BIT</span>);
    }
    <span class="cmt">//Non-const Function</span>
    <span class="kw">void</span> <span class="fn">Create</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        passingSampleCounts.<span class="fn">resize</span>(<span class="par">capacity</span>);
        passingSampleCounts.<span class="fn">shrink_to_fit</span>();
        queryPool.<span class="fn">Create</span>(<span class="enum">VK_QUERY_TYPE_OCCLUSION</span>, <span class="fn">Capacity</span>());
    }
    <span class="kw">void</span> <span class="fn">Recreate</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        <span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">WaitIdle</span>();
        queryPool.<span class="fn">~queryPool</span>();
        <span class="fn">Create</span>(<span class="par">capacity</span>);
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>() {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(<span class="par">Capacity</span>);
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>(<span class="type">uint32_t</span> <span class="par">queryCount</span>) {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(0, <span class="par">queryCount</span>, <span class="par">queryCount</span> * 4, timestamps.<span class="fn">data</span>(), 4);
    }
};
</pre></section>
</section>
<section id="id9">
<h2>管线统计查询<a class="headerlink" href="#id9" title="Permalink to this heading"></a></h2>
<p>
    在Vulkan的核心功能中（即不涉及扩展的话），可通过管线统计查询（pipeline statistics query）进行以下统计：
</p>
<table class="docutils align-default">
    <colgroup>
        <col>
        <col>
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head"><p>版本要求</p></th>
            <th class="head"><p><a href="https://renderdoc.org/vkspec_chunked/chap18.html#VkQueryPipelineStatisticFlagBits">VkQueryPipelineStatisticFlagBits</a> 的枚举项</p></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT                    </span>表示输入的顶点个数，<strong>可能</strong>计算不构成完整图元的顶点</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT                  </span>表示输入的图元个数，<strong>可能</strong>计算不完整的图元</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT                  </span>表示顶点着色器的执行次数</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT                </span>表示几何着色器的执行次数</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT                 </span>表示几何着色器生成的图元个数</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT                       </span>表示到达图元剪裁阶段的图元个数</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT                        </span>表示图元剪裁阶段输出的图元个数，计数方法为实现特定</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT                </span>表示片段着色器的执行次数，<a class="reference internal" href="Ch4-3%20%E7%89%87%E6%AE%B5%E7%9D%80%E8%89%B2%E5%99%A8.html#gl-helperinvocation">辅助调用</a>被计算在内</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT        </span>表示细分控制着色器处理的patch的个数</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT </span>表示细分求值着色器的执行次数</p></td>
        </tr>
        <tr>
            <td><p>1.0</p></td>
            <td><p><span class="enum">VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT                 </span>表示计算着色器的执行次数</p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            图元剪裁（primitive cliping）阶段指根据视见体、<a class="reference internal" href="Ch4-2%20%E9%A1%B6%E7%82%B9%E7%9D%80%E8%89%B2%E5%99%A8.html#gl-clipdistancegl">gl_ClipDistance</a>、<a class="reference internal" href="Ch4-2%20%E9%A1%B6%E7%82%B9%E7%9D%80%E8%89%B2%E5%99%A8.html#gl-culldistance">gl_CullDistance</a>，剪裁和丢弃图元的阶段。
        </p>
    </li>
    <li>
        <p>
            到达图元剪裁阶段的图元个数，与片段着色器前最后一个着色器阶段生成的图元个数一致。
        </p>
    </li>
    <li>
        <p>
            视见体（view volume）即齐次剪裁空间的可视范围，根据视见体进行剪裁，等价于只保留<a class="reference internal" href="Ch4-1%20%E7%9D%80%E8%89%B2%E5%99%A8%E6%A8%A1%E7%BB%84.html#id4">NDC坐标</a>在可渲染范围内的片段。如果绘制的图元全部在范围之外，图元剪裁阶段输出的图元个数为0。
        </p>
    </li>
</ul>
<p>
    管线统计查询可以被用于debug。
    <br>
    比如，如果图元剪裁阶段输出的图元个数非0，而片段着色器执行次数为0，那么说明片段没有通过<a class="reference internal" href="Ch4-3%20%E7%89%87%E6%AE%B5%E7%9D%80%E8%89%B2%E5%99%A8.html#early-fragment-test">早期片段测试</a>，进而检查相关参数来找出问题所在（注：对于这里所述的情况，如果开了深度测试，深度比较方式/深度清屏值的嫌疑很大）。
</p><section id="id10">
<h3>创建管线统计查询<a class="headerlink" href="#id10" title="Permalink to this heading"></a></h3>
<p>
    不涉及扩展，<span class="type">VkQueryPipelineStatisticFlagBits</span>的枚举项有11种，各个bit的总和是<code>(1 &lt;&lt; 11) - 1</code>，即2047。
    <br>
    若要进行这11个枚举项对应的所有统计，创建保存1组统计结果的查询池的代码如下：
</p>
<pre class="code">
<span class="kw">constexpr</span> <span class="type">uint32_t</span> statisticCount = 11;
<span class="type">VkQueryPoolCreateInfo</span> createInfo = {
    .queryType = <span class="enum">VK_QUERY_TYPE_PIPELINE_STATISTICS</span>,
    .queryCount = 1,
    .pipelineStatistics = (1 &lt;&lt; statisticCount) - 1
};
<span class="type">queryPool</span> queryPool(createInfo);
</pre>
<p>
    根据你向<span class="type">VkQueryPoolCreateInfo</span>::pipelineStatistics提供的数值，各项管线统计值依其对应的枚举项，按照前述<span class="type">VkQueryPipelineStatisticFlagBits</span>枚举项表格中的顺序排列。
    <br>
    特地去记忆哪个索引对应哪个统计值就太麻烦了，对于一个保存了全部11种统计值的数组，可用下述写法方便地进行访问：
</p>
<pre class="code">
<span class="kw">enum</span> <span class="type">statisticName</span> {
    <span class="cmt">//输入装配阶段</span>
    <span class="enum">vertexCount_ia</span>,           <span class="cmt">0</span>
    <span class="enum">primitiveCount_ia</span>,        <span class="cmt">1</span>
    <span class="cmt">//顶点着色器阶段</span>
    <span class="enum">invocationCount_vs</span>,       <span class="cmt">2</span>
    <span class="cmt">//几何着色器阶段</span>
    <span class="enum">invocationCount_gs</span>,       <span class="cmt">3</span>
    <span class="enum">primitiveCount_gs</span>,        <span class="cmt">4</span>
    <span class="cmt">//图元剔除阶段</span>
    <span class="enum">invocationCount_clipping</span>, <span class="cmt">5</span>
    <span class="enum">primitiveCount_clipping</span>,  <span class="cmt">6</span>
    <span class="cmt">//片段着色器阶段</span>
    <span class="enum">invocationCount_fs</span>,       <span class="cmt">7</span>
    <span class="cmt">//细分控制着色器阶段</span>
    <span class="enum">patchCount_tcs</span>,           <span class="cmt">8</span>
    <span class="cmt">//细分求值着色器阶段</span>
    <span class="enum">invocationCount_tes</span>,      <span class="cmt">9</span>
    <span class="cmt">//计算着色器阶段</span>
    <span class="enum">invocationCount_cs</span>,       <span class="cmt">10</span>
    <span class="cmt">//上述枚举项的总数</span>
    <span class="enum">statisticCount</span>            <span class="cmt">11</span>
};
<span class="type">uint32_t</span> statistics[<span class="enum">statisticCount</span>] = {};
outStream &lt;&lt; statistics[<span class="enum">invocationCount_cs</span>] &lt;&lt; <span class="str">'\n'</span>; <span class="cmt">//输出计算着色器的执行次数</span>
</pre>
<ul>
    <li>
        <p>
            这里使用了一个C++编程技巧：通过定义枚举，使用有意义的名称为索引来访问数组元素。在从0开始递增的枚举序列中，最后一个枚举项的数值会是先前所有枚举项的总数，因此还可以通过枚举来统计名称的个数。
        </p>
    </li>
</ul></section>
<section id="id11">
<h3>封装<a class="headerlink" href="#id11" title="Permalink to this heading"></a></h3>
<p>
    可对保存1组统计结果的查询池做如下封装以方便使用：
</p>
<pre class="code">
<span class="kw">class</span> <span class="type">pipelineStatisticQuery</span> {
<span class="kw">protected</span>:
    <span class="kw">enum</span> <span class="type">statisticName</span> {
        <span class="cmt">//Input Assembly</span>
        <span class="enum">vertexCount_ia</span>,
        <span class="enum">primitiveCount_ia</span>,
        <span class="cmt">//Vertex Shader</span>
        <span class="enum">invocationCount_vs</span>,
        <span class="cmt">//Geometry Shader</span>
        <span class="enum">invocationCount_gs</span>,
        <span class="enum">primitiveCount_gs</span>,
        <span class="cmt">//Clipping</span>
        <span class="enum">invocationCount_clipping</span>,
        <span class="enum">primitiveCount_clipping</span>,
        <span class="cmt">//Fragment Shader</span>
        <span class="enum">invocationCount_fs</span>,
        <span class="cmt">//Tessellation</span>
        <span class="enum">patchCount_tcs</span>,
        <span class="enum">invocationCount_tes</span>,
        <span class="cmt">//Compute Shader</span>
        <span class="enum">invocationCount_cs</span>,
        <span class="enum">statisticCount</span>
    };
    <span class="cmt">//--------------------</span>
    <span class="type">queryPool</span> queryPool;
    <span class="type">uint32_t</span> statistics[<span class="enum">statisticCount</span>] = {};
<span class="kw">public</span>:
    <span class="fn">pipelineStatisticQuery</span>() {
        <span class="fn">Create</span>();
    }
    <span class="cmt">//Getter</span>
    <span class="kw">operator</span> <span class="type">VkQueryPool</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool; }
    <span class="kw">const</span> <span class="type">VkQueryPool</span>* <span class="fn">Address</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool.<span class="fn">Address</span>(); }
    <span class="type">uint32_t</span>     <span class="fn">VertexCount_Ia</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">vertexCount_ia</span>]; }
    <span class="type">uint32_t</span>  <span class="fn">PrimitiveCount_Ia</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">primitiveCount_ia</span>]; }
    <span class="type">uint32_t</span> <span class="fn">InvocationCount_Vs</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">invocationCount_vs</span>]; }
    <span class="type">uint32_t</span> <span class="fn">InvocationCount_Gs</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">invocationCount_gs</span>]; }
    <span class="type">uint32_t</span>  <span class="fn">PrimitiveCount_Gs</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">primitiveCount_gs</span>]; }
    <span class="type">uint32_t</span> <span class="fn">InvocationCount_Clipping</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">invocationCount_clipping</span>]; }
    <span class="type">uint32_t</span>  <span class="fn">PrimitiveCount_Clipping</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">primitiveCount_clipping</span>]; }
    <span class="type">uint32_t</span> <span class="fn">InvocationCount_Fs</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">invocationCount_fs</span>]; }
    <span class="type">uint32_t</span>      <span class="fn">PatchCount_Tcs</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">patchCount_tcs</span>]; }
    <span class="type">uint32_t</span> <span class="fn">InvocationCount_Tes</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">invocationCount_tes</span>]; }
    <span class="type">uint32_t</span> <span class="fn">InvocationCount_Cs</span>() <span class="kw">const</span> { <span class="kw">return</span> statistics[<span class="enum">invocationCount_cs</span>]; }
    <span class="cmt">//Const Function</span>
    <span class="kw">void</span> <span class="fn">CmdReset</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdReset</span>(<span class="par">commandBuffer</span>, 0, 1);
    }
    <span class="kw">void</span> <span class="fn">CmdBegin</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdBegin</span>(<span class="par">commandBuffer</span>, 0);
    }
    <span class="kw">void</span> <span class="fn">CmdEnd</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdEnd</span>(<span class="par">commandBuffer</span>, 0);
    }
    <span class="kw">void</span> <span class="fn">CmdResetAndBegin</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>) <span class="kw">const</span> {
        <span class="fn">CmdReset</span>(<span class="par">commandBuffer</span>);
        <span class="fn">CmdBegin</span>(<span class="par">commandBuffer</span>);
    }
    <span class="cmt">//Non-const Function</span>
    <span class="kw">void</span> <span class="fn">Create</span>() {
        queryPool.<span class="fn">Create</span>(<span class="enum">VK_QUERY_TYPE_PIPELINE_STATISTICS</span>, 1, (1 &lt;&lt; <span class="enum">statisticCount</span>) - 1);
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>() {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(
            0,                 <span class="cmt">//firstQuery</span>
            1,                 <span class="cmt">//queryCount</span>
            <span class="kw">sizeof</span> statistics, <span class="cmt">//dataSize，内存区大小</span>
            statistics,        <span class="cmt">//pData</span>
            <span class="kw">sizeof</span> statistics  <span class="cmt">//stride，每组查询结果在目标内存区中的间距，这里是紧密排列（因为就1组结果，可以写0）</span>
        );
    }
};
</pre>
<ul>
    <li>
        <p>
            <span class="fn">VertexCount_Ia</span>()比<span class="fn">Statistic</span>(<span class="enum">vertexCount_ia</span>)短，所以就这么写了。
        </p>
    </li>
</ul></section>
</section>
<section id="id12">
<h2>时间戳查询<a class="headerlink" href="#id12" title="Permalink to this heading"></a></h2>
<p>
    在命令缓冲区的执行过程中，可写入时间戳到时间戳查询（timestamp query）。
    <br>
    时间戳查询可用于性能测试：两个时间戳相减即表明两次写入的间隔时间，即其间命令大致的执行耗时。
</p><section id="id13">
<h3>写入时间戳<a class="headerlink" href="#id13" title="Permalink to this heading"></a></h3>
<p>
    时间戳查询没有“开始”和“结束”，不对其使用<span class="fn">vkCmdBeginQuery</span>(...)和<span class="fn">vkCmdEndQuery</span>(...)。
    <br>
    相应地，在命令缓冲区中，用<a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdWriteTimestamp">vkCmdWriteTimestamp</a>(...)写入时间戳：
</p>
<table class="docutils align-default">
    <colgroup>
        <col style="width: 30%" />
        <col style="width: 70%" />
    </colgroup>
    <thead>
        <tr class="row-odd">
            <th class="head" colspan="2"><p><span class="kw">void</span> <span class="mcr">VKAPI_CALL</span> <a href="https://renderdoc.org/vkspec_chunked/chap18.html#vkCmdWriteTimestamp">vkCmdWriteTimestamp</a>(...) 的参数说明</p></th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-even">
            <td><p><span class="type">VkCommandBuffer</span> commandBuffer</p></td>
            <td><p>命令缓冲区的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">VkPipelineStageFlagBits</span> pipelineStage</p></td>
            <td><p>需要等待的管线阶段</p></td>
        </tr>
        <tr class="row-even">
            <td><p><span class="type">VkQueryPool</span> queryPool</p></td>
            <td><p>查询池的handle</p></td>
        </tr>
        <tr class="row-odd">
            <td><p><span class="type">uint32_t</span> query</p></td>
            <td><p>被写入时间戳的查询的索引</p></td>
        </tr>
    </tbody>
</table>
<ul>
    <li>
        <p>
            该命令定义执行依赖：于该命令前的命令到达pipelineStage所注明的（但凡到达得了的）阶段后，写入时间戳。
            <br>
            注意该函数不保证写入时间戳的最晚阶段，Vulkan的实现可能在先前的命令到达pipelineStage所注明的阶段后的任何阶段写入时间戳。
        </p>
    </li>
</ul>
<p>
    写入的时间戳的单位为一定量的纳秒，时间戳的数值间隔1，相当于时间上间隔<a href="https://renderdoc.org/vkspec_chunked/chap47.html#VkPhysicalDeviceLimits">VkPhysicalDeviceLimits</a>::timestampPeriod个纳秒。
</p>
<p>
    写入的时间戳的有效位数由<a href="https://renderdoc.org/vkspec_chunked/chap5.html#VkQueueFamilyProperties">VkQueueFamilyProperties</a>::timestampValidBits决定，若支持写入时间戳，则至少会有36个有效位数。
    <br>
    虽然至少会有36个有效位数，不过查询结果通常是用于计算差值的，获取到的结果是32位就足够，就算数值溢出也能算得正确的差值（除非两个时间戳之间相差的时间很大，比如<a href="https://renderdoc.org/vkspec_chunked/chap47.html#VkPhysicalDeviceLimits">VkPhysicalDeviceLimits</a>::timestampPeriod为1且两个时间戳之间相差4秒以上的情况）。
</p>
<p>
    两次写入之间存在隐式同步：对于两条<span class="fn">vkCmdWriteTimestamp</span>(...)命令，后录制的命令写入的数值所表明的时间，一定晚于先录制的命令（除非数值溢出）。
</p></section>
<section id="id14">
<h3>封装<a class="headerlink" href="#id14" title="Permalink to this heading"></a></h3>
<p>
    每组时间戳查询的查询结果是一个整形数值，既然获取到32位就够用了，对其做如下封装：
</p>
<pre class="code">
<span class="kw">class</span> <span class="type">timestampQueries</span> {
<span class="kw">protected</span>:
    <span class="type">queryPool</span> queryPool;
    std::<span class="type">vector</span>&lt;<span class="type">uint32_t</span>&gt; timestamps;
<span class="kw">public</span>:
    <span class="fn">timestampQueries</span>() = <span class="kw">default</span>;
    <span class="fn">timestampQueries</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        <span class="fn">Create</span>(<span class="par">capacity</span>);
    }
    <span class="cmt">//Getter</span>
    <span class="kw">operator</span> <span class="type">VkQueryPool</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool; }
    <span class="kw">const</span> <span class="type">VkQueryPool</span>* <span class="fn">Address</span>() <span class="kw">const</span> { <span class="kw">return</span> queryPool.<span class="fn">Address</span>(); }
    <span class="type">uint32_t</span> <span class="fn">Capacity</span>() <span class="kw">const</span> { <span class="kw">return</span> timestamps.<span class="fn">size</span>(); }
    <span class="type">uint32_t</span> <span class="fn">Timestamp</span>(<span class="type">uint32_t</span> <span class="par">index</span>) <span class="kw">const</span> { <span class="kw">return</span> timestamp[<span class="par">index</span>]; }
    <span class="cmt">/*计算两个时间戳之间的差值*/</span>
    <span class="type">uint32_t</span> <span class="fn">Duration</span>(<span class="type">uint32_t</span> <span class="par">index</span>) <span class="kw">const</span> { <span class="kw">return</span> timestamp[<span class="par">index</span> + 1] - timestamp[<span class="par">index</span>]; }
    <span class="cmt">//Const Function</span>
    <span class="cmt">/*重置整个查询池*/</span>
    <span class="kw">void</span> <span class="fn">CmdReset</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdReset</span>(<span class="par">commandBuffer</span>, 0, <span class="fn">Capacity</span>());
    }
    <span class="kw">void</span> <span class="fn">CmdWriteTimestamp</span>(<span class="type">VkCommandBuffer</span> <span class="par">commandBuffer</span>, <span class="type">VkPipelineStageFlagBits</span> <span class="par">pipelineStage</span>, <span class="type">uint32_t</span> <span class="par">queryIndex</span>) <span class="kw">const</span> {
        queryPool.<span class="fn">CmdWriteTimestamp</span>(<span class="par">commandBuffer</span>, <span class="par">pipelineStage</span>, <span class="par">queryIndex</span>);
    }
    <span class="cmt">//Non-const Function</span>
    <span class="kw">void</span> <span class="fn">Create</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        timestamps.<span class="fn">resize</span>(<span class="par">capacity</span>);
        timestamps.<span class="fn">shrink_to_fit</span>();
        queryPool.<span class="fn">Create</span>(<span class="enum">VK_QUERY_TYPE_TIMESTAMP</span>, <span class="fn">Capacity</span>());
    }
    <span class="kw">void</span> <span class="fn">Recreate</span>(<span class="type">uint32_t</span> <span class="par">capacity</span>) {
        <span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">WaitIdle</span>();
        queryPool.<span class="fn">~queryPool</span>();
        <span class="fn">Create</span>(<span class="par">capacity</span>);
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>() {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(<span class="fn">Capacity</span>());
    }
    <span class="type">result_t</span> <span class="fn">GetResults</span>(<span class="type">uint32_t</span> <span class="par">queryCount</span>) {
        <span class="kw">return</span> queryPool.<span class="fn">GetResults</span>(0, <span class="par">queryCount</span>, <span class="par">queryCount</span> * 4, timestamps.<span class="fn">data</span>(), 4);
    }
};
</pre>
<p>
    使用方式，类似这样：
</p>
<pre class="code">
<span class="type">uint32_t</span> timestampCounter = 0;
commandBuffer.<span class="fn">Begin</span>(<span class="enum">VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT</span>);

timestampQueries.<span class="fn">CmdReset</span>(commandBuffer);
timestampQueries.<span class="fn">CmdWriteTimestamp</span>(commandBuffer, <span class="enum">VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT</span>, timestampCounter++);
<span class="cmt">/*某些命令A*/</span>
timestampQueries.<span class="fn">CmdWriteTimestamp</span>(commandBuffer, <span class="enum">VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT</span>, timestampCounter++);
<span class="cmt">/*某些命令B*/</span>
timestampQueries.<span class="fn">CmdWriteTimestamp</span>(commandBuffer, <span class="enum">VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT</span>, timestampCounter++);

commandBuffer.<span class="fn">End</span>();

<span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">SubmitCommandBuffer_Graphics</span>(commandBuffer, fence);
fence.<span class="fn">Wait</span>();

timestampQueries.<span class="fn">GetResults</span>(timestampCounter);
<span class="cmt">//以毫秒单位输出时间间隔</span>
<span class="kw">for</span> (<span class="type">size_t</span> i = 0; i &lt; timestampCounter - 1; i++)
    outStream &lt&lt; timestampQueries.<span class="fn">Duration</span>(i) * <span class="type">graphicsBase</span>::<span class="sfn">Base</span>().<span class="fn">PhysicalDeviceProperties</span>().limits.timestampPeriod / 1000000.f &lt;&lt; <span class="str">'\n'</span>;
</pre></section>
</section>
</section>


           </div>
          </div>
          <footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
        <a href="Ch3-7%20%E9%87%87%E6%A0%B7%E5%99%A8.html" class="btn btn-neutral float-left" title="Ch3-7 采样器" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> 上一页</a>
        <a href="Ch4-1%20%E7%9D%80%E8%89%B2%E5%99%A8%E6%A8%A1%E7%BB%84.html" class="btn btn-neutral float-right" title="Ch4-1 着色器模组" accesskey="n" rel="next">下一页 <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
    </div>

  <hr/>

  <div role="contentinfo">
    <p>&#169; 版权所有 2021-2025, 葉橙.</p>
  </div>

  利用 <a href="https://www.sphinx-doc.org/">Sphinx</a> 构建，使用了 
    <a href="https://github.com/readthedocs/sphinx_rtd_theme">主题</a>
    由 <a href="https://readthedocs.org">Read the Docs</a>开发.
   

</footer>
        </div>
      </div>
    </section>
  </div>
  <script>
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script> 

</body>
</html>